package main.java.com.itlin.datastructure.heap;

public class MinHeap {
    int[] array;
    int size;

    public MinHeap(int capacity){
        this.array = new int[capacity];
    }

    // 构造函数
    public MinHeap(int[] array) {
        this.array = array;
        this.size = array.length;
        heapify();
    }

    //建堆操作
    void heapify(){
        //找到最后的非叶子节点
        for (int i = size/2 - 1; i >= 0 ; i--) {
            down(i);
        }
    }

    /**
     * 删除堆顶元素
     * @return 堆顶元素
     */
    public int poll() {
        int top = array[0];
        swap(0,size - 1);
        size--;
        down(0);
        return top;
    }

    /**
     * 删除指定索引处元素
     * @param index - 索引
     * @return 被删除元素
     */
    public int poll(int index){
        if (index >= size) throw new IllegalArgumentException("索引超出范围");
        int deleted = array[index];
        swap(index, size - 1);
        size--;
        down(index);
        return deleted;
    }

    /**
     * 获取堆顶元素
     * @return 堆顶元素
     */
    public int peek(){
        if (size == 0) throw new IllegalArgumentException("堆为空");
        return array[0];
    }

    /**
     * 替换堆顶元素
     * @param replaced - 新元素
     */
    public void replace(int replaced){
        if (size == 0) throw new IllegalArgumentException("堆为空");
        array[0] = replaced;
        down(0);
    }

    public boolean offer(int offered){
        if (size == array.length) throw new IllegalArgumentException("堆已满");
        up(offered);
        size++;
        return true;
    }


    // 将 offered 元素上浮： 直至 offered 大于父元素或到堆顶
    private void up(int offered){
        int child = size;
        while (child > 0) {
            int parent = (child - 1) / 2;
            if (offered < array[parent]) {
                array[child] = array[parent];
            }else{
                break;
            }
            child = parent;
        }
        array[child] = offered;
    }


    /**
     * 将 parent索引处的元素下潜： 与两个孩子较大者交换，直至没孩子或孩子没它大
     * @param parent
     */
    void down (int parent){
        int left = 2 * parent + 1;
        int right = left + 1;
        int min = parent;
        if (left < size && array[left] < array[min]){
            min = left;
        }
        if (right < size && array[right] < array[min]){
            min = right;
        }
        if (min != parent){
            swap(min, parent);
            down(min);
        }
    }

    private void swap(int i, int j){
        int t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
}
